package com.iteaj.iot.codec;

import com.iteaj.iot.ProtocolException;
import com.iteaj.iot.SocketMessage;
import com.iteaj.iot.codec.adapter.DelimiterBasedFrameMessageDecoderAdapter;
import com.iteaj.iot.codec.adapter.FixedLengthFrameDecoderAdapter;
import com.iteaj.iot.codec.adapter.LengthFieldBasedFrameMessageDecoderAdapter;
import com.iteaj.iot.codec.adapter.LineBasedFrameMessageDecoderAdapter;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import org.springframework.beans.BeanUtils;

/**
 * 报文{@link SocketMessage}解码器
 * 使用此解码器务必保留默认的报文构造函数{@link SocketMessage#SocketMessage(byte[])}
 */
public interface IotMessageDecoder {

    Class<? extends SocketMessage> getMessageClass();

    /**
     * 使用默认的构造函数 {@link SocketMessage#SocketMessage(byte[])} 构造实体报文
     * @param ctx
     * @param decode 可以是类型 ByteBuf、SocketMessage、null
     * @return SocketMessage 使用默认的构造函数 {@link SocketMessage#SocketMessage(byte[])}
     * @throws Exception
     */
    default SocketMessage proxy(ChannelHandlerContext ctx, ByteBuf decode) throws Exception {
        if(decode != null && decode.readableBytes() > 0) {
            try {
                SocketMessage message = doDecode(ctx, decode);
                if(message != null) {
                    message.setChannelId(ctx.channel().id().asShortText());
                    message.readBuild();
                }

                return message;
            } finally {
                decode.release();
            }
        } else {
            return null;
        }

    }

    /**
     * 默认只有存在数据的时候才会执行到这里, 在方法{@link #proxy(ChannelHandlerContext, ByteBuf)}做了可读数据的判断
     *
     * 使用默认构造器创建报文 {@link SocketMessage#SocketMessage(byte[])}
     *
     * 获取所有可以读的报文, 默认不进行粘包处理<hr>
     *     粘包问题再各自的适配器进行处理
     * @see FixedLengthFrameDecoderAdapter#decode(ChannelHandlerContext, ByteBuf)
     * @see LineBasedFrameMessageDecoderAdapter#decode(ChannelHandlerContext, ByteBuf)
     * @see DelimiterBasedFrameMessageDecoderAdapter#decode(ChannelHandlerContext, ByteBuf)
     * @see LengthFieldBasedFrameMessageDecoderAdapter#decode(ChannelHandlerContext, ByteBuf)
     * @param ctx
     * @param decode
     * @return
     */
    default SocketMessage doDecode(ChannelHandlerContext ctx, ByteBuf decode) {
        int readableBytes = (decode).readableBytes();

        byte[] message = new byte[readableBytes];
        (decode).readBytes(message);

        return createMessage(message);
    }

    /**
     * 创建报文对象
     * @param message
     * @return
     */
    default SocketMessage createMessage(byte[] message) {
        // 报文必须保留默认的构造函数
        try {
            return BeanUtils.instantiateClass(getMessageClass().getConstructor(byte[].class), message);
        } catch (Exception e) {
            throw new ProtocolException("找不到构造函数["+getMessageClass().getSimpleName()+"(byte[])], 请增加对应的构造函数或者自定义解码", e.getCause());
        }
    }
}
